<template>
  <teleport :to="teleportTo">
    <div
      :class="['ai-blueking-wrapper', props.extCls ?? '']"
      :style="rootVariables"
    >
      <vue-draggable-resizable
        v-if="isShow"
        ref="resizeWrapper"
        :active="isShow"
        :draggable="props.draggable"
        :h="height"
        :max-width="maxWidth"
        :min-height="minHeight"
        :min-width="minWidth"
        :parent="true"
        :prevent-deactivation="true"
        :resizable="true"
        :w="width"
        :x="left"
        :y="top"
        class-name="ai-blueking-container-wrapper"
        drag-handle=".drag-handle"
        @dragging="handleDragging"
        @resizing="handleResizing"
        @drag-stop="handleDragStop"
        @resize-stop="handleResizeStop"
      >
        <div
          ref="rootNode"
          class="ai-blueking-container"
        >
          <loading-overlay :show="isLoadingSessionContents" />
          <!-- 顶部栏 -->
          <ai-blueking-header
            v-if="!props.hideHeader"
            :title="props.title"
            :is-compression-height="isCompressionHeight"
            :draggable="props.draggable"
            :show-history-icon="props.showHistoryIcon"
            :show-new-chat-icon="props.showNewChatIcon"
            :enable-chat-session="enableChatSession"
            :chat-group="sessionStore.agentInfo.value?.chatGroup"
            :has-session-contents="hasSessionContents"
            :dropdown-menu-config="props.dropdownMenuConfig"
            :show-compression-icon="props.showCompressionIcon"
            @close="handleClose"
            @toggle-compression="toggleCompression"
            @new-chat="handleNewChat"
            @auto-generate-name="handleAutoGenerateName"
            @help-click="() => enterSelectMode('transfer')"
          />
          <div class="content-wrapper">
            <!-- 无权限提示 -->
            <div
              v-if="!hasPermission"
              class="permission-denied"
            >
              <bk-exception
                class="exception-wrap-item exception-part"
                title="暂无该智能体使用权限"
                description="请联系 admin（管理员） 处理"
                scene="part"
                type="403"
              ></bk-exception>
            </div>
            <!-- 主要内容区域 -->
            <div
              v-else
              :class="`main-content ${!hasSessionContents ? 'greeting-layout' : 'chat-layout'}`"
            >
              <greeting-section
                ref="greetingSectionRef"
                :title="props.helloText"
                :greeting-text="greetingText"
                :has-session-contents="hasSessionContents"
                :render-markdown="renderMarkdown"
                :greeting-max-height="greetingMaxHeight"
              />
              <message-list
                ref="messageListRef"
                :session-contents="sessionContents"
                :has-session-contents="hasSessionContents"
                :content-margin-bottom="contentMarginBottom"
                :is-select-mode="sessionStore.isSelectMode.value"
                :is-message-selected="sessionStore.isMessageSelected"
                @delete="handleDelete"
                @regenerate="handleRegenerate"
                @resend="handleResend"
                @message-select="sessionStore.toggleMessageSelection"
                @update-session-content="handleUpdateSessionContent"
                @scroll-position-change="handleScrollPositionChange"
              />
              <!-- 选择模式下的底部确认区域 -->
              <div
                v-if="sessionStore.isSelectMode.value"
                class="selection-footer"
              >
                <div class="selection-info">
                  <bk-checkbox
                    :model-value="isSelectAll"
                    :indeterminate="isIndeterminate"
                    label="全选"
                    @change="handleSelectAllChange"
                  />
                </div>
                <div class="selection-actions">
                  <bk-button
                    class="cancel-btn"
                    @click="handleCancelSelection"
                  >
                    {{ t('取消') }}
                  </bk-button>
                  <bk-button
                    class="confirm-btn"
                    :loading="loading"
                    theme="primary"
                    @click="handleConfirmSelection"
                  >
                    {{ t('确定') }}
                  </bk-button>
                </div>
              </div>

              <motion.div
                v-else
                :transition="{
                  duration: 0.5,
                  ease: [0.33, 1, 0.68, 1],
                  type: 'tween',
                  layoutId: 'chat-input',
                }"
                :class="`chat-input-container ${!hasSessionContents ? (props.defaultChatInputPosition ?? 'centered') : 'bottom'}`"
                :style="
                  hasSessionContents || props.defaultChatInputPosition
                    ? undefined
                    : inputContainerStyle
                "
                layout
              >
                <div class="chat-input-wrapper">
                  <div
                    v-if="currentSessionLoading || showScrollToBottom"
                    class="bottom-tools-bar"
                  >
                    <bar-button
                      v-if="currentSessionLoading"
                      color="#EA3636"
                      icon="bkai-icon bkai-tingzhishengcheng"
                      :text="t('停止生成')"
                      @click="handleStop"
                    />
                    <bar-button
                      v-if="showScrollToBottom"
                      color="#979BA5"
                      icon="bkai-icon bkai-jiantou"
                      :text="t('返回底部')"
                      @click="handleScrollMainToBottom"
                    />
                  </div>
                  <custom-input
                    v-if="currentShortcut"
                    :key="currentShortcut.id"
                    :shortcut="currentShortcut"
                    :root-node="rootNode"
                    @cancel="handleCancelShortcut"
                    @submit="handleSubmitShortcut"
                  />

                  <chat-input-box
                    v-else
                    v-model="inputMessage"
                    :class="!hasSessionContents ? 'greeting-layout' : 'chat-layout'"
                    :loading="currentSessionLoading || false"
                    :prompts="promptList"
                    :shortcuts="props.shortcuts"
                    :shortcut-filter="props.shortcutFilter"
                    :conversation-settings="sessionStore.agentInfo.value?.conversationSettings"
                    :disabled="props.disabledInput"
                    :placeholder="props.placeholder"
                    @height-change="handleInputHeightChange"
                    @send="handleSendMessage"
                    @shortcut-click="handleInputShortcutClick"
                    @stop="handleStop"
                  />
                </div>
              </motion.div>
            </div>
          </div>
        </div>
      </vue-draggable-resizable>
      <nimbus
        v-if="!props.hideNimbus"
        v-model:is-panel-show="isShow"
        v-model:is-minimize="isNimbusMinimize"
        :default-minimize="defaultMinimize"
        :size="props.nimbusSize"
        @click="handleNimbusClick"
      />
      <render-popup
        :shortcuts="props.shortcuts"
        :conversation-settings="sessionStore.agentInfo.value?.conversationSettings"
        :shortcut-limit="props.shortcutLimit"
        :shortcut-filter="props.shortcutFilter"
        :hide-default-trigger="props.hideDefaultTrigger"
        @click="isShow = true"
        @shortcut-click="handlePopupShortcutClick"
      />
    </div>
  </teleport>
</template>

<script setup lang="ts">
  // ===================================================================
  // 1. 导入和类型定义
  // ===================================================================
  import { SessionContentRole } from '@blueking/ai-ui-sdk/enums';
  import type { ISessionContent } from '@blueking/ai-ui-sdk/types';
  import { useChat, useStyle, useClickProxy } from '@blueking/ai-ui-sdk/hooks';
  import { Button as BkButton, Checkbox as BkCheckbox, Exception as BkException } from 'bkui-vue';
  import { useCopyCode } from 'markdown-it-copy-code';
  import { motion } from 'motion-v';
  import {
    computed,
    defineEmits,
    defineExpose,
    defineProps,
    nextTick,
    onBeforeUnmount,
    onMounted,
    provide,
    ref,
    Ref,
    watch,
    withDefaults,
  } from 'vue';
  import VueDraggableResizable from 'vue-draggable-resizable';

  // 组件导入
  import AiBluekingHeader from './components/ai-header.vue';
  import BarButton from './components/bar-button.vue';
  import ChatInputBox from './components/chat-input-box.vue';
  import CustomInput from './components/custom-inputs/index.vue';
  import GreetingSection from './components/greeting-section.vue';
  import LoadingOverlay from './components/loading-overlay.vue';
  import MessageList from './components/message-list.vue';
  import RenderPopup from './components/render-popup.vue';
  // Composable导入
  import { useGreetingHeight } from './composables/use-greeting-height';
  import { useMarkdown } from './composables/use-markdown';
  import { useMessageList } from './composables/use-message-list';
  import { POPUP_INJECTION_KEY } from './composables/use-popup-props';
  import { useResizableContainer } from './composables/use-resizable-container';
  import { useSelect } from './composables/use-select-pop';
  import { useSelectionMode } from './composables/use-selection-mode';
  import { provideSessionStore } from './composables/use-session-store';
  import { useShortcut } from './composables/use-shortcut';
  // 配置和工具导入
  import { HIDE_ROLE_LIST } from './config';
  import { t } from './lang';
  import type { IRequestOptions, IShortcut } from './types';
  import { escapeHtml, normalizeUrl } from './utils';
  import Nimbus from './views/nimbus.vue';

  // 样式导入
  import 'vue-draggable-resizable/style.css';
  import { AddNewSessionOptions } from './store/types';

  // 类型定义
  interface Props {
    extCls?: string;
    title?: string;
    helloText?: string;
    enablePopup?: boolean;
    shortcuts?: IShortcut[];
    shortcutLimit?: number;
    shortcutFilter?: (shortcut: IShortcut, selectedText: string) => boolean;
    hideDefaultTrigger?: boolean;
    url?: string;
    prompts?: string[];
    hideNimbus?: boolean;
    requestOptions?: IRequestOptions;
    defaultMinimize?: boolean;
    teleportTo?: string;
    draggable?: boolean;
    defaultWidth?: number;
    defaultHeight?: number;
    defaultTop?: number;
    defaultLeft?: number;
    hideHeader?: boolean;
    disabledInput?: boolean;
    nimbusSize?: 'small' | 'normal' | 'large';
    showHistoryIcon?: boolean;
    showNewChatIcon?: boolean;
    placeholder?: string;
    miniPadding?: number;
    initialSessionCode?: string;
    autoSwitchToInitialSession?: boolean;
    loadRecentSessionOnMount?: boolean;
    dropdownMenuConfig?: {
      showRename?: boolean;
      showAutoGenerate?: boolean;
      showShare?: boolean;
    };

    /**
     * 是否显示缩放图标
     * @since v1.2.9
     * @default true
     * @description 如果未定义，则显示压缩图标
     * @example
     * - true: 显示压缩图标
     * - false: 不显示压缩图标
     */
    showCompressionIcon?: boolean;

    /**
     * 是否显示更多图标
     * @since v1.2.9
     * @default true
     * @description 如果未定义，则显示更多图标
     * @example
     * - true: 显示更多图标
     * - false: 不显示更多图标
     */
    showMoreIcon?: boolean;

    /**
     * 默认输入框位置
     * @since v1.2.9
     * @default undefined
     * @description 如果未定义，则根据是否有会话内容自动判断位置
     * @example
     * - undefined: 根据是否有会话内容自动判断位置
     * - 'bottom': 底部
     */
    defaultChatInputPosition?: 'bottom' | undefined;

    /**
     * 最大宽度
     * @since v1.2.9
     * @default undefined
     * @description 如果未定义，1000px
     * @example
     * - undefined: 1000px
     * - 100: 最大宽度为 100px
     * - 100%: 最大宽度为视窗宽度
     */
    maxWidth?: number | string;
  }

  // ===================================================================
  // 2. Props 和 Emits 定义
  // ===================================================================
  const props = withDefaults(defineProps<Props>(), {
    title: '',
    extCls: '',
    helloText: t('你好，我是小鲸'),
    enablePopup: true,
    shortcuts: () => [],
    shortcutLimit: 3,
    shortcutFilter: undefined,
    hideDefaultTrigger: false,
    url: '',
    prompts: () => [],
    hideNimbus: false,
    requestOptions: () => ({}),
    defaultMinimize: false,
    teleportTo: 'body',
    draggable: true,
    defaultWidth: undefined,
    defaultHeight: undefined,
    defaultTop: undefined,
    defaultLeft: undefined,
    hideHeader: false,
    disabledInput: false,
    nimbusSize: 'normal',
    showHistoryIcon: true,
    showNewChatIcon: true,
    showCompressionIcon: true,
    showMoreIcon: true,
    placeholder: t('输入 "/" 唤出 Prompt\n通过 Shift + Enter 进行换行输入'),
    miniPadding: 0,
    initialSessionCode: '',
    autoSwitchToInitialSession: false,
    loadRecentSessionOnMount: false,
    dropdownMenuConfig: () => ({
      showRename: true,
      showAutoGenerate: true,
      showShare: false, // 默认禁用分享会话功能
    }),
    defaultChatInputPosition: undefined,
    maxWidth: 1000,
  });

  const emit = defineEmits<{
    (e: 'shortcut-click', data: { shortcut: IShortcut; source: 'popup' | 'main' }): void;
    (e: 'close' | 'show' | 'stop' | 'receive-start' | 'receive-text' | 'receive-end'): void;
    (e: 'send-message', message: string): void;
    (
      e: 'session-initialized',
      data: { openingRemark: string; predefinedQuestions: string[] }
    ): void;
    (e: 'sdk-error', data: { apiName: string; code: number; message: string; data: unknown }): void;
    (e: 'transfer-messages', messageIds: string[]): void;
    (e: 'share-messages', messageIds: string[]): void;
    (e: 'dragging', position: { x: number; y: number; width: number; height: number }): void;
    (e: 'resizing', position: { x: number; y: number; width: number; height: number }): void;
    (e: 'drag-stop', position: { x: number; y: number; width: number; height: number }): void;
    (e: 'resize-stop', position: { x: number; y: number; width: number; height: number }): void;
  }>();

  // ===================================================================
  // 3. 依赖注入
  // ===================================================================
  provide(POPUP_INJECTION_KEY, props.enablePopup);

  // 标准化的URL，自动匹配当前页面协议
  const normalizedUrl = computed(() => {
    return normalizeUrl(props.url);
  });

  // 提供给子组件使用
  provide('normalizedUrl', normalizedUrl);

  // ===================================================================
  // 4. 核心状态管理
  // ===================================================================
  // DOM引用
  const resizeWrapper = ref<InstanceType<typeof VueDraggableResizable>>();
  const chatInputBoxRef = ref<InstanceType<typeof ChatInputBox>>();
  const rootNode: Ref<HTMLElement | undefined> = ref();

  // UI状态
  const isShow = ref(false);
  const isNimbusMinimize = ref(props.defaultMinimize);
  const inputMessage = ref('');
  const showScrollToBottom = ref(false);

  // 会话状态
  const isSessionInitialized = ref(false);
  let initSessionPromise: Promise<void> | null = null;
  const openingRemark = ref('');
  const predefinedQuestions: Ref<string[]> = ref([]);

  // 窗口状态
  const windowHeight = ref(window.innerHeight);

  // 输入状态
  const inputHeight = ref(68);

  // ===================================================================
  // 5. 会话存储
  // ===================================================================
  const sessionStore = provideSessionStore();

  // ===================================================================
  // 6. 组合式 API 钩子 (Composables)
  // ===================================================================
  // 使用 markdown 渲染功能
  const { renderMarkdown } = useMarkdown();

  // 使用选择文本功能
  const { selectedText, citeText, setCiteText } = useSelect(props.enablePopup);

  // 使用消息列表功能
  const { messageListRef, scrollMainToBottom, scrollToBottomIfNeeded, resetUserScrolling } =
    useMessageList();

  // 使用快捷方式功能
  const { currentShortcut, handleShortcutClick, handleCancelShortcut } = useShortcut({
    selectedText: selectedText,
    isShow: isShow,
    handleShow: () => {
      handleShow();
    },
    handleStop: () => {
      handleStop();
    },
  });

  /**
   * 计算根元素的样式变量
   * @since v1.2.9
   * @description 计算根元素的样式变量
   * @example
   * - maxWidth: 1000px
   * - maxWidth: 100%
   * @returns {Record<string, string>}
   * @example
   * {
   *   '--ai-blueking-max-width': '1000px',
   * }
   */
  const rootVariables = computed(() => {
    const maxWidth = typeof props.maxWidth === 'number' ? `${props.maxWidth}px` : props.maxWidth;
    return {
      '--ai-blueking-max-width': maxWidth ?? '1000px',
    };
  });

  // 初始化样式和点击代理
  useStyle();
  useClickProxy();

  // ===================================================================
  // 7. UI 和布局管理 (UI & Layout)
  // ===================================================================
  // 使用可调整大小的容器
  const {
    minWidth,
    minHeight,
    maxWidth,
    top,
    left,
    width,
    height,
    isCompressionHeight,
    handleDragging,
    handleResizing,
    handleDragStop,
    handleResizeStop,
    toggleCompression,
    updatePosition,
    updateSize,
    updatePositionAndSize,
  } = useResizableContainer(
    {
      maxWidthPercent: 80,
      initWidth: props.defaultWidth,
      defaultHeight: props.defaultHeight,
      defaultTop: props.defaultTop,
      defaultLeft: props.defaultLeft,
      miniPadding: props.miniPadding,
    },
    position => {
      // 拖拽结束回调
      emit('drag-stop', position);
    },
    position => {
      // 调整大小结束回调
      emit('resize-stop', position);
    },
    position => {
      // 拖拽过程中回调
      emit('dragging', position);
    },
    position => {
      // 调整大小过程中回调
      emit('resizing', position);
    }
  );

  // 动态计算 greeting 最大高度
  const greetingMaxHeight = computed(() => windowHeight.value - 367);

  // 使用问候语高度计算功能
  const { greetingSectionRef, updateGreetingTextHeight, getInputContainerStyle } =
    useGreetingHeight({
      greetingMaxHeight: greetingMaxHeight.value,
    });

  // 计算输入框的动态位置
  const inputContainerStyle = computed(() => {
    return getInputContainerStyle(hasSessionContents.value);
  });

  // 内容边距计算
  const contentMarginBottom = computed(() => {
    const toolsBarHeight = 40;
    const offSetHeight = selectedText.value ? 100 : 70;
    return inputHeight.value + toolsBarHeight + offSetHeight;
  });

  // ===================================================================
  // 8. 聊天和会话管理 (Chat & Session)
  // ===================================================================

  // 使用聊天功能
  const {
    currentSession,
    sessionContents,
    isLoadingSessionContents,
    plusSessionContent,
    plusSessionApi,
    chat,
    stopChat,
    setCurrentSession,
    setCurrentSessionChain,
    currentSessionLoading,
    reGenerateChat,
    reSendChat,
    deleteChat,
    updateRequestOptions,
    getAgentInfoApi,
    getChatGroupApi,
    getSessionsApi,
    getSessionContentsApi,
    modifySessionApi,
    deleteSessionApi,
    renameSessionApi,
    setSessionContents,
    handleCompleteRole,
    stopSessionContentApi,
  } = useChat({
    handleStart: () => {
      scrollToBottomIfNeeded();
      emit('receive-start');
    },
    handleText: () => {
      scrollToBottomIfNeeded();
      emit('receive-text');
    },
    handleEnd: () => {
      scrollToBottomIfNeeded();
      emit('receive-end');
    },
    requestOptions: {
      url: normalizedUrl.value,
      ...props.requestOptions,
    },
    otherOptions: {
      hideReferenceDocIcon: true,
    },
  });

  // 使用选择模式功能
  const {
    handleConfirmSelection,
    handleCancelSelection,
    handleSelectAllChange,
    enterSelectMode,
    isSelectAll,
    isIndeterminate,
    loading,
  } = useSelectionMode({
    sessionStore,
    sessionContents,
    getChatGroupApi,
    onTransferMessages: messageIds => {
      emit('transfer-messages', messageIds);
    },
    onShareMessages: messageIds => {
      emit('share-messages', messageIds);
    },
  });

  // 注册 SDK 的方法
  sessionStore.registerSdkMethods({
    setCurrentSession,
    setCurrentSessionChain,
    setSessionContents,
    modifySessionApi,
    deleteSessionApi,
    renameSessionApi,
    getSessionContentsApi,
    getSessionsApi,
    getAgentInfoApi,
    plusSessionApi,
    handleCompleteRole,
    getChatGroupApi,
  });

  // 注册错误回调函数
  sessionStore.registerErrorCallback(error => {
    emit('sdk-error', error);
  });

  // 提示列表
  const promptList = computed(() => {
    return [...props.prompts, ...predefinedQuestions.value];
  });

  // 是否有会话内容
  const hasSessionContents = computed(() => {
    return sessionContents.value.filter(item => !HIDE_ROLE_LIST.includes(item.role)).length > 0;
  });

  // 是否启用会话管理
  const enableChatSession = computed(() => {
    return sessionStore.agentInfo.value?.conversationSettings?.enableChatSession ?? true;
  });

  // 是否有权限
  const hasPermission = computed(() => {
    return sessionStore.hasPermission.value;
  });

  // 问候文本
  const greetingText = computed(() => openingRemark.value || t('输入你的问题，助你高效的完成工作'));

  // ===================================================================
  // 9. 会话初始化逻辑
  // ===================================================================
  const initSession = async (loadRecentSession = false) => {
    if (initSessionPromise) {
      await initSessionPromise;
      return;
    }
    if (isSessionInitialized.value && !initSessionPromise) {
      return;
    }

    initSessionPromise = (async () => {
      try {
        const { conversationSettings } = await sessionStore.initSession(true, loadRecentSession);
        openingRemark.value = conversationSettings?.openingRemark || '';
        predefinedQuestions.value = conversationSettings?.predefinedQuestions || [];
        isSessionInitialized.value = true;

        emit('session-initialized', {
          openingRemark: openingRemark.value,
          predefinedQuestions: predefinedQuestions.value,
        });
      } finally {
        initSessionPromise = null;
        updateGreetingTextHeight();
      }
    })();

    await initSessionPromise;
  };

  // ===================================================================
  // 10. Watcher 监听器
  // ===================================================================
  watch(
    () => normalizedUrl.value,
    (newUrl, oldUrl) => {
      if (newUrl !== oldUrl && newUrl) {
        updateRequestOptions({
          url: newUrl,
          ...props.requestOptions,
        });
        isSessionInitialized.value = false;
        initSessionPromise = null;
        initSession();
      }
    }
  );

  watch(
    () => props.requestOptions,
    newOptions => {
      updateRequestOptions({
        url: normalizedUrl.value,
        ...newOptions,
      });
    },
    { deep: true }
  );

  watch(
    sessionContents,
    () => {
      nextTick(scrollToBottomIfNeeded);
    },
    { deep: true }
  );

  watch(
    () => isShow.value,
    newValue => {
      if (newValue) {
        nextTick(() => {
          chatInputBoxRef.value?.focus();
        });
      }
    }
  );

  // ===================================================================
  // 11. 生命周期钩子
  // ===================================================================
  const _switchToSession = async (sessionCode: string) => {
    if (!sessionCode) return;
    //确保在切换会话之前，会话列表已初始化
    if (!isSessionInitialized.value) {
      await initSession();
    }
    const targetSession = sessionStore.sessionList.value.find(s => s.sessionCode === sessionCode);
    if (targetSession) {
      await sessionStore.switchSessionWithContents(targetSession);
      return true;
    }
    return false;
  };
  const handleWindowResize = () => {
    windowHeight.value = window.innerHeight;
  };

  // 处理进入选择模式的自定义事件
  const handleEnterSelectMode = (event: CustomEvent<{ type: 'transfer' | 'share' }>) => {
    const { type } = event.detail;
    enterSelectMode(type);
  };

  // 使用 sendBeacon 发送停止会话请求
  const sendStopSessionRequest = () => {
    if (navigator.sendBeacon && normalizedUrl.value) {
      const stopUrl = `${normalizedUrl.value}/session_content/stop/`;

      // 使用 sendBeacon 发送 POST 请求
      const success = navigator.sendBeacon(stopUrl, new Blob(['{}'], { type: 'application/json' }));

      return success;
    } else {
      // 降级到普通的停止API调用
      stopSessionContentApi();
      return false;
    }
  };

  // 处理页面卸载事件
  const handleUnload = () => {
    sendStopSessionRequest();
  };

  onMounted(async () => {
    // 使用 unload 事件配合 sendBeacon，确保请求能够成功发送
    window.addEventListener('unload', handleUnload);
    window.addEventListener('resize', handleWindowResize);
    window.addEventListener('enter-select-mode', handleEnterSelectMode as EventListener);
    if (normalizedUrl.value && !props.defaultMinimize) {
      await initSession(props.loadRecentSessionOnMount);

      // 如果设置了初始会话代码且需要自动切换，则切换到初始会话
      if (props.initialSessionCode && props.autoSwitchToInitialSession) {
        await _switchToSession(props.initialSessionCode);
      }
    }

    useCopyCode();
  });

  onBeforeUnmount(() => {
    window.removeEventListener('resize', handleWindowResize);
    window.removeEventListener('enter-select-mode', handleEnterSelectMode as EventListener);

    // 清理页面卸载相关的事件监听器
    window.removeEventListener('unload', handleUnload);
  });

  // ===================================================================
  // 12. 事件处理函数
  // ===================================================================
  const handlePopupShortcutClick = (data: { shortcut: IShortcut; source: 'popup' | 'main' }) => {
    // 来自 render-popup 的快捷方式点击事件
    emit('shortcut-click', { shortcut: data.shortcut, source: data.source });
    handleShortcutClick(data);
  };

  const handleInputShortcutClick = (data: { shortcut: IShortcut; source: 'popup' | 'main' }) => {
    // 传递_source属性以便custom-input组件可以正确处理自动提交
    const modifiedShortcut = {
      ...data.shortcut,
      _source: data.source,
    };
    emit('shortcut-click', { shortcut: modifiedShortcut, source: data.source });
    handleShortcutClick({ shortcut: modifiedShortcut, source: data.source });
  };

  const handleInputHeightChange = (height: number) => {
    inputHeight.value = height;
  };

  const handleClose = () => {
    isShow.value = false;
    emit('close');
  };

  /**
   * @param sessionCode session code
   * @param options 创建会话参数配置
   */
  const handleShow = async (
    sessionCode?: string,
    options?: AddNewSessionOptions
  ): Promise<void> => {
    // 如果是强制新会话，先创建会话再打开面板，避免显示旧内容
    if (options?.isTemporary) {
      if (!isSessionInitialized.value) {
        await initSession();
      }

      stopChat(currentSession.value?.sessionCode);
      inputMessage.value = '';
      setCiteText('');
      // 支持用指定的 sessionCode 创建新会话，如果不提供则自动生成
      await sessionStore.addNewSession(sessionCode, options);

      // 新会话创建成功后再打开面板
      isShow.value = true;
      emit('show');
    } else {
      // 非强制新会话的情况，保持原有逻辑：先打开面板
      isShow.value = true;
      emit('show');

      if (!isSessionInitialized.value) {
        await initSession();
      }

      if (sessionCode) {
        await _switchToSession(sessionCode);
      }
    }

    updateGreetingTextHeight();
  };

  const handleNimbusClick = () => {
    handleShow();
  };

  const handleScrollMainToBottom = () => {
    scrollMainToBottom();
    // 滚动到底部后隐藏按钮
    showScrollToBottom.value = false;
  };

  const handleScrollPositionChange = (isNearBottom: boolean) => {
    // 只有当消息容器有内容且不在底部时，才显示返回底部按钮
    const messageWrapper = messageListRef.value?.messageWrapper;
    if (!messageWrapper) return;

    const { scrollHeight, clientHeight } = messageWrapper;
    showScrollToBottom.value = !isNearBottom && scrollHeight > clientHeight;
  };

  const handleSendMessage = async (message: string) => {
    if (!message.trim()) return;

    if (!isSessionInitialized.value && normalizedUrl.value) {
      await initSession();
    }

    resetUserScrolling();
    const escapedMessage = escapeHtml(message);

    await plusSessionContent(currentSession.value?.sessionCode, {
      role: SessionContentRole.User,
      content: escapedMessage,
      sessionCode: currentSession.value?.sessionCode,
      property: {
        extra: {
          cite: citeText.value,
          ...(typeof props.requestOptions?.context === 'function'
            ? props.requestOptions?.context()
            : props.requestOptions?.context),
        },
      },
    });

    // 检查是否为当前会话中的第一条用户消息
    const shouldAutoRename = isFirstUserMessageInSession();

    chat({
      sessionCode: currentSession.value?.sessionCode,
      ...props.requestOptions,
    });

    // 在发送第一条用户消息后调用renameSessionApi
    if (shouldAutoRename) {
      try {
        await autoRenameCurrentSession();
      } catch (error) {
        console.error('自动命名会话失败:', error);
      }
    }

    emit('send-message', escapedMessage);
    inputMessage.value = '';
    setCiteText('');
  };

  const handleRegenerate = (index: number) => {
    const sessionContent = sessionContents.value[index];
    if (sessionContent) {
      reGenerateChat(sessionContent.sessionCode, sessionContent, index);
    }
  };

  const handleResend = (index: number, { message }: { message: string }) => {
    const sessionContent = sessionContents.value[index];
    if (sessionContent) {
      sessionContent.content = escapeHtml(message);
      reSendChat(sessionContent.sessionCode, sessionContent, index);
    }
  };

  const handleStop = () => {
    if (currentSession?.value?.sessionCode) {
      stopChat(currentSession.value.sessionCode);
      emit('stop');
    }
  };

  const handleSubmitShortcut = async (data: {
    shortcut: IShortcut;
    formData: Record<string, any>[];
    citeFormData?: Record<string, any>[];
  }) => {
    const { shortcut, formData, citeFormData } = data;
    handleCancelShortcut();
    !isShow.value && handleShow();
    currentSessionLoading.value && handleStop();

    if (!isSessionInitialized.value && normalizedUrl.value) {
      await initSession();
    }

    // 使用 citeFormData（如果提供）否则回退到 formData
    const citeData = citeFormData || formData;

    await plusSessionContent(currentSession.value?.sessionCode, {
      role: SessionContentRole.User,
      content: shortcut.name,
      sessionCode: currentSession.value?.sessionCode,
      property: {
        extra: {
          cite: {
            type: 'structured',
            title: shortcut.name,
            data: citeData.map(item => ({
              key: item.__label,
              value: item.__value,
            })),
          },
          command: shortcut.id,
          context: [
            ...formData,
            ...(Array.isArray(props.requestOptions?.context) ? props.requestOptions.context : []),
          ],
          ...(typeof props.requestOptions?.context === 'function'
            ? props.requestOptions?.context()
            : props.requestOptions?.context),
        },
      },
    });

    // 检查是否为当前会话中的第一条用户消息
    const shouldAutoRename = isFirstUserMessageInSession();

    chat({
      sessionCode: currentSession.value?.sessionCode,
      ...props.requestOptions,
    });

    // 在发送第一条用户消息后调用renameSessionApi
    if (shouldAutoRename) {
      try {
        await autoRenameCurrentSession();
      } catch (error) {
        console.error('自动命名会话失败:', error);
      }
    }

    emit('send-message', shortcut.name);
  };

  const handleDelete = (index: number) => {
    deleteChat(index, currentSession.value?.sessionCode);
  };

  const handleUpdateSessionContent = (data: {
    messageId: number | undefined;
    updates: Partial<ISessionContent>;
  }) => {
    if (data.messageId) {
      // Find the message in sessionContents and update it
      const index = sessionContents.value.findIndex(content => content.id === data.messageId);
      if (index !== -1) {
        // Update the message properties
        const updatedContent = { ...sessionContents.value[index], ...data.updates };
        sessionContents.value[index] = updatedContent;

        // Trigger reactivity by replacing the array reference
        sessionContents.value = [...sessionContents.value];
      }
    }
  };

  // 检查是否为第一条用户消息（排除隐藏角色）
  const isFirstUserMessageInSession = () => {
    const visibleMessages = sessionContents.value.filter(
      item => !HIDE_ROLE_LIST.includes(item.role)
    );
    return visibleMessages.length === 1 && visibleMessages[0].role === SessionContentRole.User;
  };

  // 自动重命名当前会话
  const autoRenameCurrentSession = async () => {
    try {
      if (currentSession.value?.sessionCode) {
        const updatedSession = await renameSessionApi(currentSession.value.sessionCode);
        if (updatedSession?.sessionName) {
          // 更新会话存储中的会话名称
          await sessionStore.getSessionList();
        }
      }
    } catch (error) {
      console.error('自动命名会话失败:', error);
    }
  };

  // 处理自动生成命名
  const handleAutoGenerateName = async (sessionCode?: string) => {
    try {
      // 如果没有传入 sessionCode，使用当前会话的 sessionCode
      const targetSessionCode = sessionCode || currentSession.value?.sessionCode;

      if (!targetSessionCode) {
        console.error('无法获取会话代码');
        return;
      }

      console.log('开始自动生成命名，会话代码:', targetSessionCode);
      const updatedSession = await renameSessionApi(targetSessionCode);

      if (updatedSession?.sessionName) {
        // 刷新会话列表以获取最新的会话信息
        await sessionStore.getSessionList();
      }
    } catch (error) {
      console.error('自动命名失败:', error);
    }
  };

  const handleNewChat = async () => {
    stopChat(currentSession.value?.sessionCode);
    inputMessage.value = '';
    setCiteText('');
    setSessionContents([]);
  };

  // ===================================================================
  // 13. 暴露给父组件的方法
  // ===================================================================
  defineExpose({
    stopSessionContentApi,
    sessionContents,
    handleShow,
    handleClose,
    handleStop,
    handleSendMessage,
    handleShortcutClick,
    handleDelete,
    handleRegenerate,
    handleResend,
    updateRequestOptions,
    currentSessionLoading,
    isLoadingSessionContents,
    updateGreetingTextHeight,
    setCurrentSession,
    setCiteText,
    focusInput: () => {
      chatInputBoxRef.value?.focus();
    },
    // 新增会话接口
    addNewSession: (sessionCode?: string) => sessionStore.addNewSession(sessionCode),
    // 更新会话名称接口
    updateSessionName: async (sessionCode: string, newName: string) => {
      return sessionStore.updateSession(sessionCode, { sessionName: newName });
    },
    // 切换到指定会话
    switchToSession: _switchToSession,
    // 获取会话列表
    getSessionList: sessionStore.getSessionList,
    sessionList: sessionStore.sessionList,
    // 是否启用会话管理
    enableChatSession,
    // 编程式控制容器位置和大小
    updatePosition,
    updateSize,
    updatePositionAndSize,
  });
</script>

<style lang="scss" scoped>
  @use './styles/mixins.scss';
  @use './styles/markdown.scss';

  .ai-blueking-wrapper {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 10000;
    width: 100vw;
    height: 100vh;
    pointer-events: none;
  }

  .ai-blueking-container-wrapper {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    pointer-events: auto;
    background: #ffffff;
    border-radius: 2px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);

    :deep(.handle) {
      background: transparent;
      border: none;

      &.handle-ml,
      &.handle-mr {
        top: 0;
        height: 100%;
        margin-top: 0;
        cursor: ew-resize;
      }

      &.handle-tm,
      &.handle-bm {
        left: 0;
        width: 100%;
        margin-left: 0;
        cursor: ns-resize;
      }

      &.handle-tl,
      &.handle-br {
        cursor: nwse-resize;
      }

      &.handle-tr {
        top: -5px;
        right: -5px;
      }

      &.handle-tl {
        top: -5px;
        left: -5px;
      }

      &.handle-bl {
        bottom: -5px;
        left: -5px;
      }

      &.handle-br {
        right: -5px;
        bottom: -5px;
      }

      &.handle-tr,
      &.handle-bl {
        cursor: nesw-resize;
      }
    }
  }

  .ai-blueking-container {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    :deep(.icon-search::before) {
      content: none !important;
    }
  }

  .content-wrapper {
    position: relative;
    display: flex;
    flex: 1;
    overflow: hidden;
  }

  .main-content {
    position: relative;
    display: flex;
    flex: 1;
    flex-direction: column;
    min-width: 0;
    height: 100%;
    padding: 16px;
    overflow-y: auto;

    .bottom-tools-bar {
      display: flex;
      gap: 8px;
      align-items: center;
      justify-content: center;
      margin-bottom: 16px;
    }

    .message-line-wrapper {
      width: 100%;
      max-width: var(--ai-blueking-max-width);
      margin: 0 auto;
    }

    &.chat-layout {
      gap: 0;
    }

    .chat-input-wrapper {
      max-width: var(--ai-blueking-max-width);
      margin: 0 auto;
    }

    .chat-input-container {
      z-index: 3;
      width: 100%;
      outline: none;
      transform-origin: center;
      will-change: transform;

      &.centered {
        position: absolute;
        top: 188px;
        left: 50%;
        width: calc(100% - 32px);

        /* stylelint-disable-next-line declaration-no-important */
        transform: translate(-50%, 0) !important;
      }

      &.bottom {
        position: absolute;
        right: 16px;
        bottom: 16px;
        left: 16px;
        width: calc(100% - 32px);
      }
    }

    .selection-footer {
      position: absolute;
      bottom: 0;
      left: 0;
      z-index: 10;
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 100%;
      height: 46px;
      padding: 0 16px;
      background: #fafbfd;
      box-shadow: inset 0 1px 0 0 #dcdee5;

      .selection-info {
        font-size: 14px;
        color: #63656e;
      }

      .selection-actions {
        display: flex;
        gap: 8px;

        .cancel-btn {
          color: #63656e;
          background: #ffffff;
          border: 1px solid #c4c6cc;

          &:hover {
            border-color: #979ba5;
          }
        }
      }
    }
  }

  .action-icon {
    cursor: pointer;
    opacity: 0.7;

    &:hover {
      opacity: 1;
    }
  }

  // 添加 Nimbus 相关样式
  :deep(.vdr) {
    background: transparent;
    border: none;
  }

  // 无权限提示样式
  .permission-denied {
    display: flex;
    margin-top: 140px;
    justify-content: center;
    flex: 1;
    height: 100%;

    .permission-denied-content {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      padding: 40px 20px;
      text-align: center;

      .permission-icon {
        font-size: 48px;
        color: #c4c6cc;
        margin-bottom: 16px;
      }

      .permission-text {
        font-size: 18px;
        font-weight: 600;
        color: #63656e;
        margin-bottom: 8px;
      }

      .permission-desc {
        font-size: 14px;
        color: #979ba5;
      }
    }
  }
</style>
